using System;
using System.Collections.Generic;
using System.Text;
using VisualEsse.DataEngine.Types;

namespace VisualEsse.DataEngine
{
    public class NcmlGeoGridDocument : NcmlDocument
    {
        public NcmlGeoGridDocument(): base()
        {
        }

        public int LengthTime
        {
            get { return GetDimension("time"); }
        }

        public int LengthLongitude
        {
            get { return GetDimension("lon"); }
        }

        public int LengthLatitude
        {
            get { return GetDimension("lat"); }
        }

        private DateTime[] times = null;

        public DateTime[] GetTimes()
        {
            if (times != null)
                return times;

            CdmVariable v = GetVariable("time");
            float[] values = v.ParseValues();
            
            times = new DateTime[values.Length];
            DateTime origin = new DateTime(1970, 1, 1);
            for (int i = 0; i < times.Length; i++)
            {
                times[i] = origin + TimeSpan.FromDays(values[i]);
            }
            return times;
        }

        protected float[] GetLats()
        {
            CdmVariable lat = GetVariable("lat");
            float[] lats = lat.ParseValues();
            if (!lat.IsAscendencyOrder)
            {
                int l = lats.Length;
                for (int i = 0; i < l/2; i++)
                {
                    float f = lats[i];
                    lats[i] = lats[l - 1 - i];
                    lats[l - 1 - i] = f;
                }
            }
            return lats;
        }

        protected float[] GetLons()
        {
            CdmVariable lon = GetVariable("lon");
            return lon.ParseValues();
        }

        public GeoUniformGrid2d GetGrid()
        {
            float[] lats = GetLats();
            float[] lons = GetLons();

            UniformGrid1d glat = new UniformGrid1d(lats.Length, lats[0], lats[1] - lats[0]);
            UniformGrid1d glon = new UniformGrid1d(lons.Length, lons[0], lons[1] - lons[0]);
            GeoUniformGrid2d grid = new GeoUniformGrid2d(glon, glat);
            return grid;
        }

        public ScalarArray2d GetData(string parameterName, DateTime time)
        {
            ScalarArray2d[] data = GetData(parameterName);

            DateTime[] times = GetTimes();
            for (int i = 0; i < times.Length; i++)
            {
                if (times[i] == time)
                    return data[i];
            }

            throw new Exception("Data at requested moment is not available");
        }

        public ScalarArray2d[] GetData(string parameterName)
        {
            CdmVariable vals = GetVariable(parameterName);
            float[] pdata = vals.ParseValues();

            int ltimes = LengthTime;
            int llat = LengthLatitude;
            int llon = LengthLongitude;
            CdmVariable vlat = GetVariable("lat");

            if (pdata.Length !=  ltimes * LengthLongitude * LengthLatitude)
                throw new Exception("Dimensions of variables do not match");

            ScalarArray2d[] resultData = new ScalarArray2d[ltimes];
            for (int i = 0; i < resultData.Length; i++)
                resultData[i] = new ScalarArray2d(llon, llat);

            int timeIdx = 0;
            int latIdx = 0;
            int lonIdx = 0;
            int numDims = vals.Dimensions.Length;
            bool isLatAsc = vlat.IsAscendencyOrder;

            foreach (float v in pdata)
            {
                if (isLatAsc)
                    resultData[timeIdx][lonIdx, latIdx] = v;
                else
                    resultData[timeIdx][lonIdx, llat - latIdx - 1] = v;
                int dimIdx = numDims - 1;
                while (dimIdx >= 0)
                {
                    if (vals.Dimensions[dimIdx] == "lat")
                    {
                        latIdx++;
                        if (latIdx >= llat)
                        {
                            latIdx = 0;
                            dimIdx--;
                        }
                        else
                            break;
                    }
                    else if (vals.Dimensions[dimIdx] == "lon")
                    {
                        lonIdx++;
                        if (lonIdx >= llon)
                        {
                            lonIdx = 0;
                            dimIdx--;
                        }
                        else
                            break;
                    }
                    else if (vals.Dimensions[dimIdx] == "time")
                    {
                        timeIdx++;
                        if (timeIdx >= ltimes)
                        {
                            timeIdx = 0;
                            dimIdx--;
                        }
                        else
                            break;
                    }
                    else
                        throw new Exception("Unknown dimension " + vals.Dimensions[dimIdx] + " is values variable");
                }
            }

            return resultData;
        }

        public List<CdmVariable> GetValuesVariables()
        {
            List<CdmVariable> values = new List<CdmVariable>();

            foreach (CdmVariable var in vars)
            {
                if (var.Name != "time" && var.Name != "lat" && var.Name != "lon")
                    values.Add(var);
            }

            return values;
        }

    }
}
